package com.hxh.generater.springBoot.util.methodParse;

import com.hxh.generater.springBoot.util.methodParse.entity.JavaClassConst;
import com.hxh.generater.springBoot.util.methodParse.entity.JavaClassMethod;
import com.hxh.generater.springBoot.util.methodParse.entity.JavaClassParams;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 解析java类方法文件
 */
public class ParseJavaMethod {

    private static int methodCount = 0;
    private static List<JavaClassMethod> methodList = new ArrayList<>();
    private static JavaClassMethod currentMethod;

    /**
     * 判断方法行的长度，去掉 {和 }
     * 如果长度是0，则说明方法行为空，方法结束
     *
     * @param line
     * @return
     */
    private static int calculateMethodCount(String line) {
        int count = 0;
        if (StringUtils.isBlank(line)) {
            return 0;
        }
        int len = line.length();
        if (line.contains("{")) {
            //进
            count += (len - line.replaceAll("\\{", "").length());
        }
        if (line.contains("}")) {
            //出
            count -= (len - line.replaceAll("}", "").length());
        }

        return count;
    }

    private static boolean isCommentStart = false;
    private static int commentStartLine = 0;
    private static int commentEndLine = 0;

    /**
     * 从代码行中解析方法
     *
     * @param line        代码行
     * @param currentLine 当前行数
     */
    private static void processMethod(String line, int currentLine) {
        if (StringUtils.isNotBlank(line)) {
            String lineTrim = line.trim();
            if ("/**".equals(lineTrim)) {
                isCommentStart = true;
                commentStartLine = currentLine;
                return;
            } else if (isCommentStart) {
                if (lineTrim.equals("*/")) {
                    commentEndLine = currentLine;
                    isCommentStart = false;
                } else if (lineTrim.startsWith("*")) {
                    return;
                }
            }
            //判断这行是不是方法的开始
            else if (methodCount == 0 && line.contains("(") && line.contains(")") && line.contains("{")) {

                lineTrim = lineTrim.replaceAll("\\s+", " ");

                //括号前面的字符串 如 public static void aaa
                String beforeParamStr = lineTrim.substring(0, lineTrim.indexOf("("));
                String[] beforeParamStrSplit = beforeParamStr.split(" ");

                //不符合普通方法的规范
                if (beforeParamStrSplit.length < 3) {
                    return;
                }
                String methodDeclare = beforeParamStrSplit[0];
                if (!JavaClassConst.methodDeclareList.contains(methodDeclare)) {
                    return;
                }
                //符合方法的特征，开始记录方法信息
                if (currentMethod == null) {
                    currentMethod = new JavaClassMethod();
                }
                currentMethod.setMethodDeclare(methodDeclare);
                if (commentEndLine + 1 == currentLine) {
                    currentMethod.setStartLine(commentStartLine);
                }else{
                    currentMethod.setStartLine(currentLine);
                }

                currentMethod.setMethodContent(line);

                String methodName = beforeParamStrSplit[beforeParamStrSplit.length - 1];
                String returnType = beforeParamStrSplit[beforeParamStrSplit.length - 2];

                currentMethod.setMethodName(methodName);
                currentMethod.setReturnType(returnType);

                //处理方法的参数
                String methodParamStr = lineTrim.substring(lineTrim.indexOf("(") + 1, lineTrim.lastIndexOf(")"));
                String[] methodParamSplit = methodParamStr.split(",");
                List<JavaClassParams> methodParams = new ArrayList<>();
                for (String s : methodParamSplit) {
                    if (StringUtils.isBlank(s)) {
                        continue;
                    }
                    JavaClassParams javaClassParams = new JavaClassParams();
                    s = s.trim();
                    String[] sSplit = s.split(" ");
                    int sLen = sSplit.length;
                    javaClassParams.setKey(sSplit[sLen - 2]);
                    javaClassParams.setValue(sSplit[sLen - 1]);
                    if (sLen > 2) {
                        javaClassParams.setDesc(sSplit[sLen - 3]);
                    }
                    methodParams.add(javaClassParams);
                }
                currentMethod.setMethodParams(methodParams);
                methodCount = 1;
            } else if (methodCount > 0) {
                //方法已经开始了，开始记录方法体
                currentMethod.setMethodContent(currentMethod.getMethodContent() + "\n" + line);
                //这里的line不为空，如果methodCount为0，则说明方法是以}结束的，方法结束
                methodCount += calculateMethodCount(line);
            }
        }

        if (methodCount == 0 && currentMethod != null) {
            currentMethod.setEndLine(currentLine);
            methodList.add(currentMethod);
            currentMethod = null;
        }
    }

    public static List<JavaClassMethod> parser(String path) throws IOException {
        return parser(new File(path));
    }

    public static List<JavaClassMethod> parser(File template) throws IOException {
        methodCount = 0;
        methodList = new ArrayList<>();
        currentMethod = null;

        if (!template.exists()) {
            return methodList;
        }
        BufferedReader br = new BufferedReader(new FileReader(template));
        String line;

        int currentLine = 1;
        while ((line = br.readLine()) != null) {
            processMethod(line, currentLine);
            currentLine++;
        }
        br.close();
        return methodList;
    }

    /**
     * 传入一个类的所有方法，把重复的方法打上标签
     * 在文件中从上往下扫描，最后一个重复的方法不打标签
     *
     * @param list 需要扫描的方法集合
     * @return 返回所有重复的方法，就是需要抛弃的方法
     */
    public static List<JavaClassMethod> tagRepeatMethod(List<JavaClassMethod> list) {
        List<JavaClassMethod> resultList = new ArrayList<>();
        if (CollectionUtils.isEmpty(list)) {
            return resultList;
        }
        List<Integer> hashCodeList = new ArrayList<>();
        Map<Integer, List<JavaClassMethod>> listHashMap = new HashMap<>();

        for (JavaClassMethod javaClassMethod : list) {
            int hashCode = javaClassMethod.hashCode();
            if (hashCodeList.contains(hashCode)) {
                //旧的method，全部打上重复的标签
                List<JavaClassMethod> list1 = listHashMap.get(hashCode);
                list1.forEach(st -> st.setRepeat(true));
                //新的method，没有打上便签
                list1.add(javaClassMethod);
                listHashMap.put(hashCode, list1);
            } else {
                List<JavaClassMethod> list1 = new ArrayList<>();
                list1.add(javaClassMethod);
                listHashMap.put(hashCode, list1);
                hashCodeList.add(hashCode);
            }
        }
        for (JavaClassMethod javaClassMethod : list) {
            if (javaClassMethod.isRepeat()) {
                resultList.add(javaClassMethod);
            }
        }
        return resultList;
    }
}
